Skip to content

feat: add agentcore import command for starter toolkit migration#620

Merged
jesseturner21 merged 30 commits intoaws:mainfrom
jesseturner21:main
Mar 26, 2026
Merged

feat: add agentcore import command for starter toolkit migration#620
jesseturner21 merged 30 commits intoaws:mainfrom
jesseturner21:main

Conversation

@jesseturner21
Copy link
Copy Markdown
Contributor

@jesseturner21 jesseturner21 commented Mar 24, 2026

Description

Adds a new agentcore import CLI command that migrates existing Bedrock AgentCore Starter Toolkit projects into the agentcore-cli.

Problem

Users who started with the Starter Toolkit have deployed agents, memories, and credentials via .bedrock_agentcore.yaml. To adopt the CLI's richer feature set (TUI, multi-target deploys, evaluations, etc.), they need a migration path that preserves their existing AWS resources without downtime or re-creation.

Solution

The import command implements a 3-phase CloudFormation migration flow:

  1. Phase 1 (UPDATE): Deploys companion resources (IAM roles, policies) into a new or existing CloudFormation stack, filtering out primary AgentCore resources. Dangling Ref/Fn::GetAtt references to removed resources are replaced with "*" placeholders.

  2. Phase 2 (IMPORT): Uses CloudFormation's IMPORT change set mechanism to adopt pre-existing AWS::BedrockAgentCore::Runtime and AWS::BedrockAgentCore::Memory resources into the stack, with DeletionPolicy: Retain to prevent accidental deletion.

  3. Phase 3 (user runs agentcore deploy): Reconciles the full stack with the real synthesized CDK template, replacing placeholders and adding back DependsOn relationships.

Key capabilities

  • YAML parsing: Custom parser for .bedrock_agentcore.yaml format (handles agents, memories, credentials, VPC config, OAuth/API key providers, container vs CodeZip builds)
  • Config merge: Merges imported agents/memories/credentials into an existing agentcore.json, skipping duplicates
  • Source code copy: Copies agent source to app/<name>/, handles symlinks, excludes .venv/__pycache__/etc., copies Dockerfiles for container builds, fixes setuptools auto-discovery issues
  • Idempotency: Re-running import skips already-imported resources (tracks newly added vs existing)
  • Undeployed support: Agents with agent_id: null skip CloudFormation phases entirely (config-only merge)
  • CDK bootstrap: Auto-bootstraps the AWS environment if not already done
  • Target resolution: Auto-creates deployment target from YAML if none exists, supports --target for multi-target projects
  • UX warnings: Memory env var mismatch (diff-style hint), custom JWT authorizer not imported, account/region mismatch

New files

File Purpose
src/cli/commands/import/actions.ts Main orchestration: YAML parse → config merge → source copy → Phase 1 → Phase 2 → state update
src/cli/commands/import/command.ts Commander registration, CLI output formatting, warning collection
src/cli/commands/import/constants.ts CFN resource identifiers, primary resource types, runtime type map
src/cli/commands/import/index.ts Barrel export
src/cli/commands/import/phase1-update.ts Phase 1: CREATE/UPDATE stack with companion-only template
src/cli/commands/import/phase2-import.ts Phase 2: IMPORT change set creation/execution, CDK asset publishing
src/cli/commands/import/template-utils.ts CFN template manipulation: filter, build import template, find logical IDs
src/cli/commands/import/types.ts TypeScript interfaces for parsed config, import results
src/cli/commands/import/yaml-parser.ts Minimal YAML parser for starter toolkit config format

Modified files

File Change
esbuild.config.mjs Add jsx: 'automatic' to match tsconfig's react-jsx
src/cli/cli.ts Register the import command
src/cli/operations/deploy/pre-deploy-identity.ts Skip OAuth setup when discoveryUrl missing
src/cli/tui/utils/commands.ts Add import to HIDDEN_FROM_TUI
src/schema/schemas/agentcore-project.ts Make discoveryUrl optional in OAuthCredentialSchema

Related Issue

Closes #

Documentation PR

Type of Change

  • New feature
  • Bug fix
  • Breaking change
  • Documentation update
  • Other (please describe):

Testing

How have you tested the change?

  • I ran npm run test:unit and npm run test:integ
  • I ran npm run typecheck
  • I ran npm run lint
  • If I modified src/assets/, I ran npm run test:update-snapshots and committed the updated snapshots

Unit tests added (8 test files, ~200 tests)

Test file Coverage
container-agent-import.test.ts Container/CodeZip deployment types, runtime mapping, Dockerfile handling
idempotency.test.ts Re-import skips existing resources, partial overlap, credential dedup
import-memory.test.ts Memory mode parsing, STM/LTM strategies, event expiry clamping, typeof guard
import-no-deploy.test.ts Undeployed agents (null IDs), config-only merge, no CFN operations
merge-logic.test.ts Append-only merge, duplicate detection, source copy skip
multi-agent.test.ts 2/3 agents, shared memory dedup, similar names, credentials extraction
test1-no-memory-agent.test.ts Single agent no-memory path, YAML parsing, template operations
vpc-import.test.ts VPC network config, Array.isArray guards, subnet/security group parsing

Manual testing

  • TUI renders without crash after jsx fix
  • import does not appear in interactive command picker
  • agentcore import --source <yaml> works for: single agent, multi-agent, container builds, undeployed agents, re-import idempotency
  • Tested on unbootstrapped accounts (auto-bootstrap works)
  • Lint, prettier, secretlint, typecheck all pass

Checklist

  • I have read the CONTRIBUTING document
  • I have added any necessary tests that prove my fix is effective or my feature works
  • I have updated the documentation accordingly
  • I have added an appropriate example to the documentation to outline the feature, or no new docs are needed
  • My changes generate no new warnings
  • Any dependent changes have been merged and published

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the
terms of your choice.

@jesseturner21 jesseturner21 requested a review from a team March 24, 2026 17:53
@jesseturner21 jesseturner21 changed the title fix: import command bugbash fixes (TUI crash, memory warnings, hide from menu) feat: add agentcore import command for starter toolkit migration Mar 24, 2026
@github-actions github-actions Bot added the size/xl PR size: XL label Mar 24, 2026
@jesseturner21 jesseturner21 marked this pull request as draft March 24, 2026 18:17
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Mar 24, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Mar 24, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Mar 24, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Mar 24, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Mar 26, 2026
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Mar 26, 2026
jesseturner21 and others added 12 commits March 26, 2026 15:43
…containers

Two fixes:
1. Memory name prefix mismatch: CDK prefixes memory names with project
   name (e.g. "myproject_Agent_mem") but import searched for unprefixed
   YAML name. Added fallback lookup with project name prefix.
2. Container agents no longer trigger unnecessary Python venv setup
   during import, since dependencies are installed inside the Docker image.

Constraint: CDK BasePrimitiveConstruct generates physicalName as ${projectName}_${name}
Rejected: Stripping prefix from CDK names | would break other CDK conventions
Confidence: high
Scope-risk: narrow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
esbuild does not read tsconfig.json, so it defaults to classic JSX
transform (React.createElement) while tsconfig specifies react-jsx
(automatic). This produces 432 bare React.createElement calls in the
bundle that reference a nonexistent React global, crashing all TUI
commands (status, deploy, etc.) with "React is not defined".

Constraint: esbuild ignores tsconfig jsx settings by default
Rejected: Adding React as external | would require React in node_modules at runtime
Confidence: high
Scope-risk: narrow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Starter Toolkit injects memory ID via BEDROCK_AGENTCORE_MEMORY_ID,
but CDK constructs use MEMORY_{NAME}_ID pattern. After import, agent
code still references the old env var, causing memory to silently fail.

Add a yellow warning during import telling users the correct env var
name to update in their agent code.

Constraint: CDK env var naming is controlled by AgentCoreMemory.getEnvVarName()
Rejected: Auto-rewrite agent source code | too fragile across frameworks
Confidence: high
Scope-risk: narrow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
The Starter Toolkit injects memory ID via BEDROCK_AGENTCORE_MEMORY_ID,
but CDK constructs use MEMORY_{NAME}_ID pattern. After import, agent
code still references the old env var, causing memory to silently fail.

Show a git-diff-style warning during import with red/green highlighting
so users see exactly what to change in their agent code.

Constraint: CDK env var naming is controlled by AgentCoreMemory.getEnvVarName()
Rejected: Auto-rewrite agent source code | too fragile across frameworks
Confidence: high
Scope-risk: narrow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Import is a CLI-only command that requires --source flag and doesn't
have a TUI screen. Remove it from the interactive command picker.

Confidence: high
Scope-risk: narrow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Import fails with "The specified bucket does not exist" when the AWS
account hasn't been CDK-bootstrapped. The deploy command handles this
via useCdkPreflight, but import bypasses that since it's CLI-only.

Check bootstrap status after CDK synth and auto-bootstrap if needed,
before disposing the toolkit wrapper.

Tested on two unbootstrapped accounts (509471412906, 126432121770).

Constraint: Must bootstrap before disposing toolkitWrapper since bootstrap requires it
Rejected: Prompt user to manually run cdk bootstrap | poor UX for import flow
Confidence: high
Scope-risk: narrow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Remove unused waitUntilChangeSetCreateComplete import
- Prefix unused assetHash with underscore
- Add eslint-disable for necessary any cast in STS credentials
- Remove unnecessary type assertion in test
- Fix prettier formatting in multi-agent test

Confidence: high
Scope-risk: narrow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
OAuthCredentialProvider.discoveryUrl was made optional to support imported
providers that already exist in Identity service. Update tests to match:
- Schema test: expect success when discoveryUrl is omitted
- Pre-deploy identity tests: add discoveryUrl to fixtures that test
  update and error paths (without it, the code now skips the provider)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…rAllMocks

checkBootstrapNeeded and bootstrapEnvironment were created as inline
vi.fn() inside the vi.mock factory. vi.clearAllMocks() in beforeEach
wipes their mockResolvedValue, causing handleImport to fail in CI
where test execution order differs from local runs.

Hoist the mocks and configure them in setupCommonMocks like all other
mock functions in the file.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
When import fails during CDK build/synth or CloudFormation phases, the
merged config (agentcore.json) was already written to disk. On retry,
the import would detect existing agents and report false success without
completing the CloudFormation import. This snapshots the original config
before merging and restores it if any later phase fails.

Constraint: Rollback only triggers after config is written (configWritten flag)
Constraint: Snapshot must be a deep clone since projectSpec is mutated in-place
Rejected: Deferred config write until after all phases | too invasive, changes control flow for all paths
Confidence: high
Scope-risk: narrow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
STM_ONLY memories incorrectly received a SEMANTIC strategy in the import
flow, while the CLI create flow and starter toolkit both deploy STM_ONLY
with zero strategies. This mismatch caused drift/errors during reconciliation.

Constraint: Must match CLI create flow which maps shortTerm to strategies: []
Rejected: Keep SEMANTIC for STM_ONLY | causes reconciliation drift with deployed resources
Confidence: high
Scope-risk: narrow

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…it YAML

Instead of warning users to manually recreate the gateway, the import
pipeline now reads authorizer_configuration.customJWTAuthorizer from
the starter toolkit YAML and writes authorizerType/authorizerConfiguration
to agentcore.json so CDK handles it automatically.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Resolves npm ci failure caused by missing yaml@2.8.3 transitive
dependency required by vitest/vite and lint-staged.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions github-actions Bot added size/xl PR size: XL and removed size/xl PR size: XL labels Mar 26, 2026
Copy link
Copy Markdown
Contributor

@tejaskash tejaskash left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good. Well-structured feature with strong test coverage.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/xl PR size: XL

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants